﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace OverlayAp
{
    public partial class MainFrm : Form
    {
        public struct LogData
        {
            public double TimeStamp;
            public double[] DataArray;
        }

        public List<string> ColumnNames = new List<string>();
        public List<LogData> DataList = new List<LogData>();

        public const double FrameRate = 25;
        public Size FrameSize = new Size(1280, 720);

        public MainFrm()
        {
            InitializeComponent();
        }

        private void buttonOpenLog_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string filename = openFileDialog1.FileName;
                WriteDbg(string.Format("Opening file {0}...", filename));

                // clear old data
                ColumnNames.Clear();
                DataList.Clear();

                // parse file
                StreamReader str = File.OpenText(filename);
                string column =str.ReadLine();
                string[] names = column.Split(' ');
                ColumnNames.AddRange(names);

                // read the rest
                string line = "";
                while( (line = str.ReadLine()) != null )
                {
                    string[] tokens = line.Split(' ', '\t');
                    if (tokens.Length != ColumnNames.Count) continue; // error

                    // add to list
                    LogData ld = new LogData();
                    ld.TimeStamp = double.Parse(tokens[1]);

                    ld.DataArray = new double[tokens.Length];
                    for (int i = 0; i != tokens.Length; i++)
                    {
                        ld.DataArray[i] = double.Parse(tokens[i]);
                    }

                    if (ld.TimeStamp == 0) continue; // skip zero timestamp (first, invalid entry!)
                       DataList.Add(ld);
                }
                str.Close();

                // update log
                WriteDbg(string.Format("Found {0} Columns", ColumnNames.Count));
                WriteDbg(string.Format("Parsed {0} Rows", DataList.Count));
                WriteDbg(string.Format("First Timestamp: {0} sec.", DataList[0].TimeStamp));
                WriteDbg(string.Format("Last Timetamp: {0} sec.", DataList[DataList.Count - 1].TimeStamp));

                int totalImagesToCreate = (int)((DataList[DataList.Count - 1].TimeStamp - DataList[0].TimeStamp)*FrameRate);
                WriteDbg(string.Format("Will create {0} images", totalImagesToCreate));
                WriteDbg(string.Format("Output Folder: {0}", Application.StartupPath));
            }
            
        }

        private void WriteDbg(string txt)
        {
            richTextBox1.AppendText(txt + Environment.NewLine);
            richTextBox1.ScrollToCaret();
        }

        private void buttonDoImages_Click(object sender, EventArgs e)
        {
            WriteDbg(string.Format("Creating images..."));
            double CurrentTimeStamp = DataList[0].TimeStamp;
            double LastTimeStamp = DataList[DataList.Count - 1].TimeStamp;
            int fileIndex = 0;
            do
            {
                // get logdata chunk
                LogData data = FindLogDataChunk(CurrentTimeStamp);
                
                // create and save image
                SaveImage(fileIndex++, data);

                // increase timestamp
                CurrentTimeStamp += (1.0 / FrameRate);

            } while (CurrentTimeStamp < LastTimeStamp);
            WriteDbg(string.Format("{0} Images done", fileIndex));
        }

        private void buttonTestSingle_Click(object sender, EventArgs e)
        {
            SaveImage(0, DataList[0]);
        }

        private void SaveImage(int idx, LogData data)
        {
            // create new bitmap
            Bitmap bmp = new Bitmap(FrameSize.Width, FrameSize.Height);
            Graphics g = Graphics.FromImage(bmp);
            g.Clear(Color.Transparent);
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            Font font = new Font("Arial", 24, FontStyle.Bold);
            SolidBrush brush = new SolidBrush(Color.OrangeRed);
            PointF drawPoint = new PointF(150.0F, 150.0F);
            

            // draw data
            // TimeSec TotalTime Voltage PWM1 PWM2 Current1 Power1 Force1 Torque1 RPM1 Omega Yaw MagYaw
            // Timestamp
            int ypos = 500;
            string textTS = string.Format("Time: {0:0.00} sec.", data.DataArray[GI("TotalTime")] );
            g.DrawString(textTS, font, brush, 10, ypos+=35);

            // Voltage
            string voltageS = string.Format("Voltage: {0:0.00} V", data.DataArray[GI("Voltage")]);
            g.DrawString(voltageS, font, brush, 10, ypos += 35);

            string alt = string.Format("Altitude: {0:0.00} m", data.DataArray[GI("Alt")]);
            g.DrawString(alt, font, brush, 10, ypos += 35);

            string vertSpeed = string.Format("Vertical Speed: {0:0.00} m/s", data.DataArray[GI("VertSpeed")]);
            g.DrawString(vertSpeed, font, brush, 10, ypos += 35);

            /*
            // Current
            string currentS = string.Format("Current: {0:0.0} A", data.DataArray[GI("Current1")]);
            g.DrawString(currentS, font, brush, 10, ypos += 25);

            // Current
            string powerS = string.Format("Power: {0:0.0} W", data.DataArray[GI("Power1")]);
            g.DrawString(powerS, font, brush, 10, ypos += 25);

            // PWMs
            string pwmS = string.Format("PWM1/PWM2: {0}/{1}", data.DataArray[GI("PWM1")], data.DataArray[GI("PWM2")]);
            g.DrawString(pwmS, font, brush, 10, ypos += 25);

            // Force
            string forceS = string.Format("Force: {0:0.00} kg", data.DataArray[GI("Force1")]);
            g.DrawString(forceS, font, brush, 10, ypos += 25);

            // Omega
            string omegaS = string.Format("Ang. Vel: {0:0.0} deg/s", data.DataArray[GI("Omega")]/Math.PI*180);
            g.DrawString(omegaS, font, brush, 10, ypos += 25);

            // Yaw
            string yawS = string.Format("Angle: {0:0.0} deg", data.DataArray[GI("MagYaw")] / Math.PI * 180);
            g.DrawString(yawS, font, brush, 10, ypos += 25);

            // draw yaw
            double Angle = data.DataArray[GI("MagYaw")] - 60*Math.PI/180;

            float X = (float)Math.Cos(Angle);
            float Y = (float)Math.Sin(Angle);
            Pen p1 = new Pen(Color.White, 5);
            Pen p2 = new Pen(Color.Blue, 3);
            Pen p3 = new Pen(Color.White, 1);
            g.DrawLine(p1, 20, 400, 220, 400);
            g.DrawLine(p1, 120, 300, 120, 500);
            g.DrawLine(p2, 120, 400, 120 + X * 90, 400 + Y * 90);
            g.DrawString("Angle", font, Brushes.Blue, 90, 510);

            // Force
            g.DrawLine(p1, 20, 600, 340, 600);
            g.DrawLine(p1, 20, 550, 20, 650);
            Font fontMini = new Font("Arial", 12);
            for (int i = 1; i != 11; i++)
            {
                g.DrawLine(p3, 20 + i * 30, 580, 20 + i * 30, 620);
                g.DrawString(string.Format("{0:0.0}", i * 0.1), fontMini, Brushes.White, 5 + i * 30, 550);
            }
            float pos = (float)(data.DataArray[GI("Force1")]*10);
            g.DrawLine(p2, 20 + pos * 30, 570, 20 + pos * 30, 630);
            g.DrawString("Force [kg]", font, Brushes.Blue, 130, 650);
            */

            // save image
            string filename = string.Format("Image{0:00000}.png", idx);
            bmp.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
            g.Dispose();
            bmp.Dispose();
        }

        private int GI(string p)
        {
            return ColumnNames.FindIndex(item => item == p);
        }

        private LogData FindLogDataChunk(double CurrentTimeStamp)
        {
            LogData ret = DataList[0];

            for (int i = 0; i != DataList.Count; i++)
            {
                if (CurrentTimeStamp > DataList[i].TimeStamp)
                {
                    ret = DataList[i];
                }
            }

            return ret;
        }
    }
}
